package com.huawei.util;

import java.sql.*;

public class DBManagerPerf {

    /**
     * @Description 加载JDBC驱动
     */
    static {
        try {
            // static Class<?> | forName(String
            // className)返回与带有给定字符串名的类或接口相关联的Class 对象。
            // Class.forName("com.mysql.jdbc.Driver");
            Class.forName("org.postgresql.Driver");
        } catch (ClassNotFoundException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }

    /**
     * @throws SQLException
     * @Description 创建连接对象(建立数据库连接)
     */
    // java.sql 接口 Connection 与特定数据库的连接（会话）。在连接上下文中执行 SQL 语句并返回结果。
    public static Connection openConnection(String url, String us, String ps) throws SQLException {
        if (url.isEmpty()) {
            throw new NullPointerException("数据库URL配置为空, 请检查! ");
        }
        if (us.isEmpty()) {
            throw new NullPointerException("数据库账号配置为空，请检查! ");
        }
        if (ps.isEmpty()) {
            throw new NullPointerException("数据库密码配置为空，请检查! ");
        }
        return DriverManager.getConnection(url.trim(),
                us.trim(), ps.trim());
    }

    /**
     * @throws SQLException
     * @Description 关闭链接
     */
    public static void closeConnection(Connection conn) throws SQLException {
        // boolean | isClosed()查询此 Connection 对象是否已经被关闭
        if (conn != null && !conn.isClosed()) {
            // void | close()立即释放此 Connection 对象的数据库和 JDBC 资源，而不是等待它们被自动释放。
            conn.close();
        }
    }

    /*
     * 当我们执行完一条Sql语句，获取到一个 ResultSet 对象后，有时我们需要立即知道到底返回了多少个元素，但是 ResultSet 并没有提供一个
     *      size() 方法 or length 的属性，我们可以一个一个调用 next() 去累加计算，但是我们还有更好的办法：
     *      PreparedStatement statement = ......;
     *      ResultSet results = statement.executeQuery();
     *      // 将游标移动到最后一行上 results.last();
     *      // 得到当前的 row number，在 JDBC 中，row number 从1开始，所以这里就相当于行数 int rowCount = results.getRow();
     *
     *      //此时游标执行了最后一行，如果我们后面还想从头开始调用 next()遍历整个结果集，我们可以将游标移动到第一行前面
     *      results.beforeFirst();
     *
     *      // 通过上述这步操作，我们算是回复了结果集到初始状态（即刚查询出来的状态）
     *
     *      注意：上述这一系列移动游标的操作是有前提的，我们的结果集必须是 scrollable(可滚动的)！这个是由 statement 对象决定，我们在创建
     *
     *      statement 对象可以指定如下参数：
     *
     *      conn = getConnection(); statement = conn.prepareStatement(sql,
     *      ResultSet.TYPE_SCROLL_INSENSITIVE,
     *      ResultSet.CONCUR_READ_ONLY); 通过上述 statement 获取的 ResultSet 就是可以滚动的，如果我们只是 conn.prepareStatement(sql) 来获取的
     *
     *      statement 对象，是不可以滚动的（只可以调用 next() 向前遍历），调用任何上述移动游标的方法，都会抛出 SQLException
     *
     *      ResultSet 还为我们定义了如下常量：
     *      ResultSet.TYPE_FORWARD_ONLY只能向前滚动
     *      ResultSet.TYPE_SCROLL_INSENSITIVE和 Result.
     *      TYPE_SCROLL_SENSITIVE这两个方法都能够实现任意的前后滚动，使用各种移动的ResultSet指针的方法。
     */

    /**
     * @param conn 数据库连接名
     * @param sql  查询语句
     * @param obs  object类的数组 用于存放查询语句的参数
     * @return 结果集
     * @throws SQLException
     * @Description 执行有结果集查询命令 - 查询
     **/
// java.sql 接口 ResultSet 表示数据库结果，据表，通常通过执行查询数据库的语句生成。
    public static ResultSet query(Connection conn, String sql, Object[] obs) throws SQLException {
        ResultSet rs = null;
        if (conn != null && !conn.isClosed()) {
            // java.sql 接口 PreparedStatement 表示预编译的 SQL 语句的对象。
            // PreparedStatement | prepareStatement(String sql) 创建一个 PreparedStatement
            // 对象来将参数化的 SQL 语句发送到数据库。
            PreparedStatement psment = conn.prepareStatement(sql,
                    ResultSet.TYPE_SCROLL_INSENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
            if (obs != null) {
                for (int i = 0; i < obs.length; i++) {
                    // void | setObject(int parameterIndex, Object x)使用给定对象设置指定参数的值。
                    // 这个类型的索引位置从1开始(i+1)
                    psment.setObject(i + 1, obs[i]);
                }
            }
            // ResultSet | executeQuery() 在此 PreparedStatement 对象中执行 SQL 查询，并返回该查询生成的
            // ResultSet 对象。
            rs = psment.executeQuery();
        }
        return rs;
    }

    /**
     * @throws SQLException
     * @Description 执行无结果集命令 - 修改
     */
    public static int update(Connection conn, String sql, Object... obs) throws SQLException {
        int rs = 0;
        if (conn != null) {
            PreparedStatement psment = conn.prepareStatement(sql);
            if (obs != null) {
                for (int i = 0; i < obs.length; i++) {
                    psment.setObject(i + 1, obs[i]);
                }
            }
            // int executeUpdate()在此 PreparedStatement 对象中执行 SQL 语句，该语句必须是一个 SQL 数据操作语言（Data
            // Manipulation Language，DML）语句，比如 INSERT、UPDATE 或 DELETE 语句；或者是无返回内容的 SQL 语句，比如
            // DDL 语句。
            rs = psment.executeUpdate();
        }
        return rs;
    }
}
